﻿using System;
using System.Threading;
using System.Windows.Forms;
using Bioinformatics.Types;
using Bioinformatics.UI.eUtilsFetchSequence;

namespace EntrezBrowser
{
    public partial class DownloadForm : Form
    {
        public DownloadForm()
        {
            InitializeComponent();
        }

        public GeneticSequence DownloadedSequence { get; set; }
        public eFetchRequest GenomeRequest { get; set; }
        public int MaximumPacketSequenceLength { get; set; }
        public int SequenceStartBase { get; set; }
        public int SequenceLength { get; set; }

        private void BeginDownload()
        {
            var sequence = new char[SequenceLength];

            int completed = -1;
            var downloadFailed = false;

            Parallel.For(0, SequenceLength / MaximumPacketSequenceLength, i =>
                                                                            {
                                                                                var request = new eFetchRequest
                                                                                                  {
                                                                                                      db =
                                                                                                          GenomeRequest.
                                                                                                          db,
                                                                                                      id =
                                                                                                          GenomeRequest.
                                                                                                          id,
                                                                                                      seq_start =
                                                                                                          (SequenceStartBase +
                                                                                                           (i*
                                                                                                            MaximumPacketSequenceLength)
                                                                                                               .ToString
                                                                                                               ()),
                                                                                                      seq_stop =
                                                                                                          (SequenceStartBase +
                                                                                                           ((i + 1)*
                                                                                                            MaximumPacketSequenceLength)
                                                                                                               .
                                                                                                               ToString())
                                                                                                  };

                                                                                var server =
                                                                                    new eUtilsServiceSoapClient();
                                                                                try
                                                                                {
                                                                                    var result =
                                                                                        server.run_eFetch(request);
                                                                                    Array.Copy(
                                                                                        result.GBSet.GBSeq[0].
                                                                                            GBSeq_sequence.
                                                                                            ToCharArray(), 0, sequence,
                                                                                        Convert.ToInt32(
                                                                                            request.seq_start),
                                                                                        MaximumPacketSequenceLength);
                                                                                    completed++;
                                                                                    UpdateProgress(completed,
                                                                                                   (SequenceLength/
                                                                                                    MaximumPacketSequenceLength) -
                                                                                                   1);
                                                                                }
                                                                                catch (Exception)
                                                                                {
                                                                                    downloadFailed = true;
                                                                                }
                                                                            });

            if (downloadFailed)
            {
                MessageBox.Show(
                    "There was an error with downloading the requested sequence from the NCBI database, please try again.");
                DialogResult = DialogResult.Abort;
            }
            else
            {
                DownloadedSequence.Sequence = new string(sequence);
                DialogResult = DialogResult.OK;
            }
        }

        private void UpdateProgress(int progress, int total)
        {
            if (uxDownloadProgress.InvokeRequired)
                Invoke(new MethodInvoker(() => uxDownloadProgress.Value = (int) (((float) progress/total)*100)));
            else
                uxDownloadProgress.Value = (int) (((float) progress/total)*100);
        }

        private void DownloadForm_Load(object sender, EventArgs e)
        {
            var downloadThread = new Thread(BeginDownload);
            downloadThread.Start();
        }
    }
}